package com.example.formula;

import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;

import java.math.BigDecimal;
import java.util.function.BiFunction;

/**
 * 公式运算工具类
 * @author shanchong
 * @date 2021/1/29
 **/
public class FormulaUtils {

    public static void main(String[] args) {
        String json = "[{\"arithmetic\":\"sub\",\"value\":1},{\"arithmetic\":\"div\",\"value\":3}]";
        BigDecimal bigDecimal1 = BigDecimal.valueOf(10);
        bigDecimal1 = compete(json, bigDecimal1);
        System.out.println("bigDecimal1:" + bigDecimal1);
    }

    /**
     * 使用公式计算
     * @param json 约定好的json格式的公式
     *             例如：[{"arithmetic":"sub","value":1},{"arithmetic":"div","value":3}]，意思是：(N-1)/3
     * @param bigDecimal 运算前的数值
     * @return 运算后的结果
     */
    public static BigDecimal compete(final String json, BigDecimal bigDecimal) {
        JsonArray asJsonArray = new JsonParser().parse(json).getAsJsonArray();
        for (JsonElement jsonElement: asJsonArray) {
            JsonObject asJsonObject = jsonElement.getAsJsonObject();
            String arithmetic = asJsonObject.get("arithmetic").getAsString();
            BigDecimal value = asJsonObject.get("value").getAsBigDecimal();
            bigDecimal = Arithmetic.valueOfCode(arithmetic).getFunction().apply(bigDecimal, value);
        }
        return bigDecimal;
    }

    public enum Arithmetic {
        /**
         * 加减乘除
         */
        NONE("none", (a,b)->a),
        ADD("add", BigDecimal::add),
        SUBTRACTION("sub", BigDecimal::subtract),
        MULTIPLICATION("mul", BigDecimal::multiply),
        DIVISION("div", (a,b)->{
            return a.divide(b,2, BigDecimal.ROUND_HALF_DOWN);
        });

        private final String code;
        private final BiFunction<BigDecimal, BigDecimal, BigDecimal> function;

        Arithmetic(String code, BiFunction<BigDecimal, BigDecimal, BigDecimal> function) {
            this.code = code;
            this.function = function;
        }

        public static Arithmetic valueOfCode(String code) {
            Arithmetic[] values = values();
            for (final Arithmetic value : values) {
                if (value.getCode().equals(code)) {
                    return value;
                }
            }
            return NONE;
        }

        public String getCode() {
            return code;
        }

        public BiFunction<BigDecimal, BigDecimal, BigDecimal> getFunction() {
            return function;
        }
    }


}
